import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:get/get.dart';
import 'package:ichinesereader/controller/reports.dart';
import 'package:ichinesereader/exam/dto/assessment.response.dart';
import 'package:ichinesereader/exam/widgets/BGSinglePlayer.dart';
import 'package:ichinesereader/models/assessment/assessmentRecordsGradesResult.dart';
import 'package:ichinesereader/models/common/StatusMessageResult.dart';
import 'package:ichinesereader/service/assessment.dart';
import 'package:ichinesereader/utils/StrUtil.dart';
import 'package:ichinesereader/utils/helper.dart';
import 'package:ichinesereader/utils/log.dart';

class TeacherRunningRecordController extends GetxController {
  RxInt stepTop = (-1).obs;
  AssessmentResult? assessmentResult;
  ExamRunningRecord? recordsGrades;
  RxList<ArticleWord>? articleList = <ArticleWord>[].obs;
  bool isCompleted = true;
  RxInt fluencyScore = (-1).obs;
  final TextEditingController textController = TextEditingController();
  final TextEditingController messageTextController = TextEditingController();
  Map<String, dynamic> partTwoScoreMap = {};
  String articleStr = '';
  Rx<bool> isNextEnable = false.obs;
  String reviewHtmlStr = '';
  ScrollController scrollCrl = ScrollController();

  List statusList = [
    ['Omission', 'omission'],
    ['Insertion', 'insertion'],
    ['Substitution', 'substitution'],
    ['Repetition', 'repetition'],
    ['Self-Correction', 'selfCorrection'],
    ['Incorrect Tones', 'incorrectIntonation']
  ];

  List behaviorErrorList = [
    ['Errors: M', 'errorsMeaning'],
    ['Errors: S', 'errorsSyntax'],
    ['Errors: V', 'errorsVisual']
  ];
  List behaviorSelfList = [
    ['Self-Correction: M', 'selfCorrectionMeaning'],
    ['Self-Correction: S', 'selfCorrectionSyntax'],
    ['Self-Correction: V', 'selfCorrectionVisual']
  ];
  List behaviorTList = [
    ['Incorrect Tone: T', 'incorrectIntonationTonal']
  ];

  int _totalScoreNum = 0;

  RxList<List> scoreList = [
    ['Scorecard', '', 0, true],
    ['Errors', 'reset', 1, true],
    ['Counted Errors', 0, 2, true],
    ['Omissions', 0, 4, false],
    ['Insertions', 0, 3, false],
    ['Substitutions', 0, 4, false],
    ['Non-counted Errors', 0, 2, true],
    ['Repetitions', 0, 4, false],
    ['Self-Corrections', 0, 3, false],
    ['Incorrect Tones', 0, 4, false],
    ['Score', '', 1, true],
    ['TWC', 0, 4, false],
    ['Error Rate', '', 3, false],
    ['Accuracy Rate', '100.00%', 4, false]
  ].obs;

  RxList<List> behaviorScoreList = [
    ['Scorecard', '', 0],
    ['MSVT', 'reset', 1],
    ['Errors', '', 2],
    ['M', 0, 4],
    ['S', 0, 3],
    ['V', 0, 4],
    ['Self-Corrections', '', 2],
    ['M', 0, 4],
    ['S', 0, 3],
    ['V', 0, 4],
    ['Incorrect Tones', '', 2],
    ['T', 0, 4]
  ].obs;
  final AssessmentServiceProvider _service = AssessmentServiceProvider();

  void dealPageControl(bool isNext) {
    if (isNext) {
      stepTop++;
    } else {
      stepTop--;
    }
    isNextEnable.value = false;
    switch (stepTop.value) {
      case 0:
        {
          if (fluencyScore.value > -1) isNextEnable.value = true;
          break;
        }
      case 1:
        {
          bool isHave = true;
          partTwoScoreMap.forEach((key, value) {
            if (value == '-1') isHave = false;
          });
          if (isHave) isNextEnable.value = true;
          break;
        }
      case 2:
      case 3:
      case 4:
        isNextEnable.value = true;
    }
  }

  void nextPage() {
    dealPageControl(true);
  }

  void prevPage() {
    dealPageControl(false);
  }

  Future<void> getArticleTextInfo(String bookId) async {
    EasyLoading.show();

    var questions = assessmentResult!.list![1].questions!;
    for (var question in questions) {
      partTwoScoreMap[question.id!] = '-1';
    }

    String? oralStr = recordsGrades!.oralJson;
    if (oralStr != null) {
      Map<String, dynamic> oralDic = json.decode(oralStr);
      oralDic.forEach((key, value) {
        if (partTwoScoreMap.containsKey(key)) {
          partTwoScoreMap[key] = value;
        }
      });
    }
    try {
      var result = await _service.getArticleTextInfo(bookId);
      articleStr = '<div style="white-space:pre">$result<h3>&nbsp;</h3><div>';
      nextPage();
    } catch (e) {
      Log.debug(e);
    } finally {
      EasyLoading.dismiss();
    }
  }

  Future<void> getExaminationReportHtml(String recordId) async {
    EasyLoading.show();
    try {
      var result = await _service.getExaminationReportHtml(recordId);
      reviewHtmlStr = json.decode(result!)['result']['html'];
      nextPage();
    } catch (e) {
      Log.debug(e);
    } finally {
      EasyLoading.dismiss();
    }
  }

  Future<void> submitPageData() async {
    if (stepTop.value == 2) {
      getExaminationReportHtml(recordsGrades!.questionRecordId!);
      return;
    }

    if (isCompleted) {
      if (StrUtil.hasValue(articleStr)) {
        if (stepTop.value > 2) {
          Get.back();
          return;
        }
        nextPage();
      } else {
        if (StrUtil.hasValue(assessmentResult!.bookId)) {
          getArticleTextInfo(assessmentResult!.bookId!);
        }
      }
      return;
    }
    EasyLoading.show();
    try {
      ExamRunningRecord dto = ExamRunningRecord();
      // step == 0
      dto.assessmentId = recordsGrades!.assessmentId;
      dto.questionRecordId = recordsGrades!.questionRecordId;
      dto.userName = recordsGrades!.userName;
      int? textTotal = recordsGrades!.textTotal;
      dto.textTotal =
          (textTotal != null && textTotal > 0) ? textTotal : _totalScoreNum;
      if (fluencyScore.value != 0) dto.fluencyScore = fluencyScore.value;
      if (scoreList.length == 15) {
        if (!isCompleted) {
          if (scoreList[14][1] == '') {
            dto.accuracyRate = null;
          } else {
            dto.accuracyRate = int.parse(scoreList[14][1]);
          }
        }
      }
      Map errorMap = {};
      for (int i = 0; i < articleList!.length; i++) {
        var item = articleList![i];
        if (item.status != '') {
          errorMap[item.key] = item.status;
        }
      }
      if (errorMap.isNotEmpty) {
        String errorJson = json.encode(errorMap);
        dto.errorsJson = errorJson;
      }

      // step == 1
      if (stepTop > 0) {
        int oralScore = 0;
        partTwoScoreMap.forEach((key, value) {
          oralScore += int.parse(value);
        });
        String oralJson = json.encode(partTwoScoreMap);
        dto.oralJson = oralJson;
        dto.oralScore = oralScore;
      }

      // step == 3 || 4
      if (stepTop > 2) {
        dto.submit = true;
        dto.comment = messageTextController.text;
        Map behaviorMap = {};
        for (int i = 0; i < articleList!.length; i++) {
          var item = articleList![i];
          if (item.behavior != '') {
            behaviorMap[item.key] = item.behavior;
          }
        }
        if (behaviorMap.isNotEmpty) {
          String behaviorJson = json.encode(behaviorMap);
          dto.msvtErrorsJson = behaviorJson;
        }
      }

      Map jsonList = dto.toJson()..removeWhere((key, value) => value == null);
      //todo 如果Update Accuracy Rate 删除后，不论传0还是null，都是无效的,需要后端修改
      if (dto.accuracyRate == null && !jsonList.containsKey("accuracyRate")) {
        jsonList["accuracyRate"] = null;
      }
      String dtoJson = json.encode(jsonList);
      var result = await _service.submitAssessmentGrade(dtoJson);
      if (result.statusCode == 200) {
        var status = statusMessageResultFromJson(result.bodyString);
        if (status.status == 1000) {
        } else {
          return;
        }
      } else {
        return;
      }
      if (StrUtil.hasValue(articleStr)) {
        if (stepTop > 2) {
          Get.back();
          return;
        }
        nextPage();
      } else {
        if (StrUtil.hasValue(assessmentResult!.bookId)) {
          getArticleTextInfo(assessmentResult!.bookId!);
        }
      }
    } catch (e) {
      Log.debug(e);
    } finally {
      Future.delayed(const Duration(milliseconds: 500), () {
        EasyLoading.dismiss();
      });
    }
  }

  void dealBehaviorDataWithScoreList(bool isReset) {
    behaviorScoreList[3][1] = 0;
    behaviorScoreList[4][1] = 0;
    behaviorScoreList[5][1] = 0;
    behaviorScoreList[7][1] = 0;
    behaviorScoreList[8][1] = 0;
    behaviorScoreList[9][1] = 0;
    behaviorScoreList[11][1] = 0;

    for (int i = 0; i < articleList!.length; i++) {
      var item = articleList![i];
      if (isReset) {
        item.behavior = '';
      } else {
        if (item.behavior == behaviorErrorList[0][1]) behaviorScoreList[3][1]++;
        if (item.behavior == behaviorErrorList[1][1]) behaviorScoreList[4][1]++;
        if (item.behavior == behaviorErrorList[2][1]) behaviorScoreList[5][1]++;
        if (item.behavior == behaviorSelfList[0][1]) behaviorScoreList[7][1]++;
        if (item.behavior == behaviorSelfList[1][1]) behaviorScoreList[8][1]++;
        if (item.behavior == behaviorSelfList[2][1]) behaviorScoreList[9][1]++;
        if (item.behavior == behaviorTList[0][1]) behaviorScoreList[11][1]++;
      }
    }

    behaviorScoreList.refresh();
    if (isReset) articleList!.refresh();
  }

  void dealDataWithScoreList(bool isReset) {
    scoreList[2][1] = 0;
    scoreList[3][1] = 0;
    scoreList[4][1] = 0;
    scoreList[5][1] = 0;

    scoreList[6][1] = 0;
    scoreList[7][1] = 0;
    scoreList[8][1] = 0;
    scoreList[9][1] = 0;
    scoreList[11][1] = _totalScoreNum.toString();

    for (int i = 0; i < articleList!.length; i++) {
      var item = articleList![i];
      if (isReset) {
        item.status = '';
        if (i == articleList!.length - 1) {
          scoreList[14][1] = '';
          textController.text = scoreList[14][1];
        }
      } else {
        if (item.status == statusList[0][1] ||
            item.status == statusList[1][1] ||
            item.status == statusList[2][1]) {
          scoreList[2][1]++;
          if (item.status == statusList[0][1]) scoreList[3][1]++;
          if (item.status == statusList[1][1]) scoreList[4][1]++;
          if (item.status == statusList[2][1]) scoreList[5][1]++;
        }
        if (item.status == statusList[3][1] ||
            item.status == statusList[4][1] ||
            item.status == statusList[5][1]) {
          scoreList[6][1]++;
          if (item.status == statusList[3][1]) scoreList[7][1]++;
          if (item.status == statusList[4][1]) scoreList[8][1]++;
          if (item.status == statusList[5][1]) scoreList[9][1]++;
        }
      }
    }

    scoreList[12][1] =
        scoreList[2][1].toString() + ' : ' + _totalScoreNum.toString();
    var score = ((_totalScoreNum - scoreList[2][1]) * 100 / _totalScoreNum)
        .toStringAsFixed(2);
    scoreList[13][1] = score + '%';
    scoreList.refresh();
    if (isReset) articleList!.refresh();
  }

  Future<void> getAssessmentByStudentName(
      String assessmentId, String studentName, String questionRecordId) async {
    EasyLoading.show();
    try {
      var result =
          await _service.getAssessmentByStudentName(assessmentId, studentName);
      assessmentResult = result;
      getAssessmentGrade(questionRecordId);
    } catch (e) {
      Log.debug(e);
    } finally {
      EasyLoading.dismiss();
    }
  }

  Future<void> getAssessmentGrade(String questionRecordId) async {
    EasyLoading.show();
    try {
      var response = await _service.getAssessmentGrade(questionRecordId);
      if (response.statusCode == 200) {
        AssessmentRecordsGradesResult data =
            AssessmentRecordsGradesResult.fromJson(
                json.decode(response.bodyString));
        if (data.result != null) {
          recordsGrades = data.result!.runningRecord;
          int? score = recordsGrades!.fluencyScore;
          if (score != null && score > 0) fluencyScore.value = score;
          String? jsonUrl =
              assessmentResult!.list![0].questions![0].question![0].head!.json;
          var result = await _service.getArticleInfo(jsonUrl!);
          isCompleted = (assessmentResult!.recordStatus == 'COMPLETED');
          if (StrUtil.hasValue(recordsGrades!.comment)) {
            messageTextController.text = recordsGrades!.comment!;
          }
          if (!isCompleted && scoreList.length == 14) {
            int? accuracyRate = recordsGrades!.accuracyRate;
            List<Object> inputRow = [
              'Update Accuracy Rate',
              (accuracyRate == null || accuracyRate == 0)
                  ? ''
                  : accuracyRate.toString(),
              4,
              false
            ];
            scoreList.add(inputRow);
            textController.text = scoreList[14][1];
          } else if (isCompleted &&
              recordsGrades!.accuracyRate != null &&
              recordsGrades!.accuracyRate! > 0 &&
              scoreList.length == 14) {
            List<Object> inputRow = [
              'Updated Accuracy Rate',
              recordsGrades!.accuracyRate!.toString() + '%',
              4,
              false
            ];
            scoreList.add(inputRow);
            textController.text = scoreList[14][1];
          }
          // 计算TWC并将errorsJson赋值到articleList
          if (result != null) {
            articleList = RxList<ArticleWord>.from(
                json.decode(result).map((x) => ArticleWord.fromJson(x)));
            _totalScoreNum = 0;
            String? errorsStr = recordsGrades!.errorsJson;
            Map<String, dynamic> errorDic = {};
            if (errorsStr != null) {
              errorDic = json.decode(errorsStr);
            }
            for (int i = 0; i < articleList!.length; i++) {
              var item = articleList![i];
              if (item.value != ' ' && item.value != '\r\n') {
                _totalScoreNum++;
                if (errorDic.isNotEmpty && errorDic.containsKey(item.key)) {
                  item.status = errorDic[item.key] ?? '';
                }
              }
            }
            dealDataWithScoreList(false);

            String? behaviorErrorsStr = recordsGrades!.msvtErrorsJson;
            Map<String, dynamic> behaviorErrorDic = {};
            if (behaviorErrorsStr != null) {
              behaviorErrorDic = json.decode(behaviorErrorsStr);
            }
            for (int i = 0; i < articleList!.length; i++) {
              var item = articleList![i];
              if (item.value != ' ' && item.value != '\r\n') {
                if (behaviorErrorDic.isNotEmpty &&
                    behaviorErrorDic.containsKey(item.key)) {
                  item.behavior = behaviorErrorDic[item.key] ?? '';
                }
              }
            }
            dealBehaviorDataWithScoreList(false);
            nextPage();
          }
        }
      }
    } catch (e) {
      Log.debug(e);
    } finally {
      EasyLoading.dismiss();
    }
  }

  void downloadReport() async {
    String fileId = recordsGrades!.questionRecordId!;
    final ReportsController _reportsController = ReportsController();
    try {
      _reportsController.downloadGradeReport(fileId).then((fileResult) {
        if (fileResult.result != null && fileResult.result?.fileLink != null) {
          launchInWebViewWithJavaScript(
              _reportsController.gradeReport.value.result!.fileLink!);
        }
      });
    } catch (e) {
      print("eerror :::: $e");
    }
  }

  @override
  void onClose() {
    BGSinglePlayer().stop();
    textController.dispose();
    messageTextController.dispose();
    scrollCrl.dispose();
    super.onClose();
  }
}
